package net.seehope.foodie.web.config;

import java.util.Properties;

import javax.sql.DataSource;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import org.springframework.security.web.authentication.rememberme.JdbcTokenRepositoryImpl;
import org.springframework.security.web.authentication.rememberme.PersistentTokenRepository;

import net.seehope.foodie.properties.BrowserProperties;
import net.seehope.foodie.properties.ProjectConstant;
import net.seehope.foodie.properties.ProjectProperties;
import net.seehope.foodie.properties.ValidateCodeFilter;
import net.seehope.foodie.web.config.handler.FailureHandler;
import net.seehope.foodie.web.config.handler.SuccessHandler;

/*
 *1. 认证  有很多种方法进行认证，session,cookie,
 *2. 鉴权
 * 攻击防护
 */

//安全配置
@Configuration
public class WebSecurityConfiguration extends WebSecurityConfigurerAdapter {
	
	@Autowired
	private ProjectProperties properties;
	
	@Autowired
	private SuccessHandler successHandler;
	
	@Autowired
	private FailureHandler failureHandler;
	
	@Autowired
	private DataSource dataSource;
	
	@Autowired
	private UserDetailsService userDetailsService;
	
	@Bean
	public PersistentTokenRepository persistentTokenRepository() {
		JdbcTokenRepositoryImpl tokenRepository = new JdbcTokenRepositoryImpl();
		tokenRepository.setDataSource(dataSource);
		//仅能执行一次，需要手动注释
		//tokenRepository.setCreateTableOnStartup(true);
		return tokenRepository;
	}
	
	@Override
	protected void configure(HttpSecurity http) throws Exception {
		BrowserProperties browser = properties.getBrowser();
		
		ValidateCodeFilter validateCodeFilter = new ValidateCodeFilter();
		validateCodeFilter.setFailureHandler(failureHandler);
		validateCodeFilter.setProperties(properties);
		validateCodeFilter.afterPropertiesSet();
		
		//将自定义的过滤器validateCodeFilter添加到系统过滤器UsernamePasswordAuthenticationFilter之前
		
		//选择当前认证方式 http.httpBasic()
		http.addFilterBefore(validateCodeFilter, UsernamePasswordAuthenticationFilter.class).formLogin()// 配置了httpUsernamePassword登录方式
				.loginPage(ProjectConstant.LOGIN_PAGE)//当用户没有认证的时候，跳转的路径
				.loginProcessingUrl(browser.getLoginProcessingUrl())//登录表单的form中的action的路径,会覆盖系统本身的
				.successHandler(successHandler)//配置登录成功处理
				.failureHandler(failureHandler)//配置登录失败处理
				.and()// 返回http对象，在这里即表示返回上一层，没返回之前都是对之前属性的配置
				.rememberMe()//接下来都是对记住我功能的配置
				.tokenRepository(persistentTokenRepository())//设置token存储的地方
				.tokenValiditySeconds(properties.getBrowser().getTokenValidateSeconds())//设置token的有效期
				.userDetailsService(userDetailsService)//从token中获取到用户名之后，走哪一个userDetailService
				.and()
				
				//-------------------------------------------------------------------------
				
				.authorizeRequests()// 接下来的配置都是对授权的配置,当如下路径请求发生时
				.antMatchers(browser.getLoginPage(),ProjectConstant.LOGIN_PAGE,browser.getLoginProcessingUrl(),
				ProjectConstant.VALIDATE_CODE_GENERATOR_URL+"/*",ProjectConstant.MOBILE_AUTHENTICATION_URL)//当请求匹配到这些路径的时候放行
				.permitAll()//允许访问
				.anyRequest()// 所有的请求
//		.permitAll()//都允许通过
				.authenticated()// 都必须认证之后才允许访问
				.and()// 返回http配置
				.csrf()// csrf攻击防护
				.disable();// 暂时关闭
	}

	// 下面这个密码加密在spring当中已经有了，我们只需要把他注入进容器即可
	// springsecurity当中已经提供了这个类

	 @Bean 
	 public PasswordEncoder passwordEncoder() { 
	return new BCryptPasswordEncoder(); }
	 

}
